/*
# MIAHX© 框架消息 FastDDS API 的包装类（Nodejs端）

Version: 0.4.10,
Last updated: October 22, 2024

## Contributor(s)
* YAO Naiming <[naiming@iscas.ac.cn](mailto:naiming@iscas.ac.cn)>

## Change log
### v0.4.10
- .22: [更新] 新增发布 veh_name 字段
- .19: [更新] 新增用户感知数据发布；新增对 ecu_trip 数据的发布
- .17: [更新] 新增三维点云模态的自车轨迹数据发布
- .17: [更新] JSON 数据中新增 topic 字段，区分消息主题；发布数据样本的 iid 和 uts
- .16: [更新] 重命名，新增注释
### v0.4.7
- .26: [新增] 初始实现

---
Copyright © 2024-2025 MIAHX Contributors, ISCAS, and ASIC. All Rights Reserved.
Licensed under Apache-2.0.
*/

#include "../include/miahx_nodejs_wrapper.h"
#include "../include/miahx/bng_classical_reader.h"
#include "../include/miahx/point_cloud_reader.h"
#include "../include/miahx/user_reader.h"

using json = nlohmann::json;


static std::recursive_mutex mtx;


MiahxWrapperNodejs *MiahxWrapperNodejs::get_instance() {
    static MiahxWrapperNodejs instance;
    return &instance;
}

MiahxWrapperNodejs::MiahxWrapperNodejs()
        : mParticipant(new Participant()),
          mBngClassicalReader(nullptr),
          mPointCloudReader(nullptr) {
}

MiahxWrapperNodejs::~MiahxWrapperNodejs() {
    if (nullptr != mPointCloudReader) {
        auto ptr = (PointCloudStreamReader *) mPointCloudReader;
        delete ptr;
    }
    if (nullptr != mBngClassicalReader) {
        auto ptr = (BngClassicalStreamReader *) mBngClassicalReader;
        delete ptr;
    }
    if (nullptr != mParticipant) {
        auto ptr = (Participant *) mParticipant;
        delete ptr;
    }
}

void MiahxWrapperNodejs::set_bng_classical_data_provider(
        DATA_PROVIDER provider, void *user_state) {
    mtx.lock();
    if (nullptr != mBngClassicalReader) {
        // pass
    } else {
        data_listener listener([=](void *ptr) {
            auto frame = (BngClassicalDataFrame *) ptr;
            json j_frames = json::array();
            auto &hdr = frame->header();
            auto &source = hdr.header().source();
            auto &samples = frame->samples();
            for (auto &sample: samples) {
                auto obj = json::object();
                obj["iid"] = sample.iid();
                obj["uts"] = sample.uts();
                obj["veh_name"] = sample.veh_name();
                obj["ecu_wheelspeed"] = sample.ecu_wheelspeed();
                obj["ecu_gear"] = sample.ecu_gear();
                obj["ecu_trip"] = sample.ecu_trip();
                obj["road_speed_limit"] = sample.road_speed_limit();
                j_frames.push_back(obj);
            }
            json j_data = json::object();
            j_data["source"] = source;
            j_data["topic"] = TOPIC_BNG_CLASSICAL;
            j_data["samples"] = j_frames;
            auto result = j_data.dump();
            if (nullptr != provider) {
                provider(result.c_str(), user_state);
            }
        });
        auto participant = (Participant *) mParticipant;
        mBngClassicalReader = new BngClassicalStreamReader(participant, listener, user_state);
    }
    mtx.unlock();
}

void MiahxWrapperNodejs::set_car_trajectory_data_provider(
        DATA_PROVIDER provider, void *user_state) {
    mtx.lock();
    if (nullptr != mPointCloudReader) {
        // pass
    } else {
        data_listener listener([=](void *ptr) {
            auto frame = (PointCloudDataFrame *) ptr;
            json j_frames = json::array();
            auto &hdr = frame->header();
            auto &source = hdr.header().source();
            auto &samples = frame->samples();
            for (auto &sample: samples) {
                auto obj = json::object();
                obj["iid"] = sample.iid();
                obj["uts"] = sample.uts();
                obj["points"] = json::array();
                auto points = sample.points();
                for (size_t i = 0; i < points.size(); i += 3) {
                    auto j_point = json::object();
                    j_point["x"] = points[i];
                    j_point["y"] = points[i + 1];
                    j_point["z"] = points[i + 2];
                    obj["points"].push_back(j_point);
                }
                j_frames.push_back(obj);
            }
            json j_data = json::object();
            j_data["source"] = source;
            j_data["topic"] = TOPIC_CAR_TRAJECTORY_PC;
            j_data["samples"] = j_frames;
            auto result = j_data.dump();
            if (nullptr != provider) {
                provider(result.c_str(), user_state);
            }
        });
        auto participant = (Participant *) mParticipant;
        mPointCloudReader = new PointCloudStreamReader(participant, TOPIC_CAR_TRAJECTORY_PC,
                                                       listener, user_state);
    }
    mtx.unlock();
}

void MiahxWrapperNodejs::set_usr_driver_intention_data_provider(
        DATA_PROVIDER provider, void *user_state) {
    mtx.lock();
    if (nullptr != mUserReader) {
        // pass
    } else {
        data_listener listener([=](void *ptr) {
            auto frame = (UserDataFrame *) ptr;
            json j_frames = json::array();
            auto &hdr = frame->header();
            auto &source = hdr.header().source();
            auto &samples = frame->samples();
            for (auto &sample: samples) {
                auto obj = json::object();
                obj["iid"] = sample.iid();
                obj["uts"] = sample.uts();
                obj["ditype"] = sample.ditype();
                j_frames.push_back(obj);
            }
            json j_data = json::object();
            j_data["source"] = source;
            j_data["topic"] = TOPIC_USR_DRIVER_INTENTION;
            j_data["samples"] = j_frames;
            auto result = j_data.dump();
            if (nullptr != provider) {
                provider(result.c_str(), user_state);
            }
        });
        auto participant = (Participant *) mParticipant;
        mUserReader = new UserStreamReader(participant, TOPIC_USR_DRIVER_INTENTION,
                                           listener, user_state);
    }
    mtx.unlock();
}
